package com.itheima.tlias.aop;

import com.itheima.tlias.anno.LogAnno;
import com.itheima.tlias.domain.OperateLog;
import com.itheima.tlias.mapper.OperateLogMapper;
import com.itheima.tlias.utils.JwtUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.Arrays;

/**
 * @author ghy
 * @version 1.0.1
 * @date 2024-01-30 15:42:06
 */
@Component
@Aspect
@Slf4j
public class LogAspect {

    public static final String TOKEN = "token";

    @Autowired
    private OperateLogMapper operateLogMapper;

    @Autowired
    private HttpServletRequest request;

    //切点
    //@Pointcut("execution(* com.itheima.tlias.web.controller.*.*(..))")
    @Pointcut("execution(* com.itheima.tlias.web.controller.*.*(..)) && @annotation(com.itheima.tlias.anno.LogAnno)")
    public void pt(){}

    //通知
    @Around("pt()")
    public Object around(ProceedingJoinPoint pjp){
        log.info("日志环绕通知开始了:{}", pjp);
        Object result = null;
        OperateLog operateLog = new OperateLog();
        long start = System.currentTimeMillis();
        try {
            String token = request.getHeader(TOKEN);
            Object empId = JwtUtils.parseJwt(token).get("id");   //操作人ID
            MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
            String className = pjp.getTarget().getClass().getName();  //全类名
            Method method = methodSignature.getMethod();
            String methodName = method.getName();  //方法名
            LogAnno logAnno = method.getAnnotation(LogAnno.class);
            String methodDesc = logAnno.methodDesc();   //方法描述
            Object[] args = pjp.getArgs();
            String methodParams = Arrays.toString(args);    //方法参数
            operateLog.setOperateUser(Integer.valueOf(empId.toString()));
            operateLog.setOperateTime(LocalDateTime.now());
            operateLog.setClassName(className);
            operateLog.setMethodName(methodName);
            operateLog.setMethodDesc(methodDesc);
            operateLog.setMethodParams(methodParams);
            result = pjp.proceed();
            operateLog.setReturnValue(result.toString());   //返回值
        } catch (Throwable e) {
            e.printStackTrace();
            operateLog.setReturnValue("出异常了，返回值为异常消息：" + e.getMessage());  //返回值
        } finally {
            long end = System.currentTimeMillis();
            operateLog.setCostTime(end - start);   //执行时长
        }
        operateLogMapper.save(operateLog);
        return result;
    }

}
